package com.hzdesk.media.koreabatchmatvector.custom;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;


import com.hzdesk.media.koreabatchmatvector.bean.DcfBean;
import com.hzdesk.media.koreabatchmatvector.bean.PathBean;
import com.hzdesk.media.koreabatchmatvector.bean.SerPath;
import com.hzdesk.media.koreabatchmatvector.bean.SerPoint;
import com.hzdesk.media.koreabatchmatvector.config.AppConfig;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author Mr.Lee
 */
public class DeskmediaCanvas extends View {
    private static final String TAG = "DeskmediaCanvas";
    private Canvas mCanvas;
    private long startTime;
    private Bitmap bitmap;
    private DcfBean mBean;
    private Paint mPaint;
    public Timer mTimer, pathTimer;
    private long currentTime, length;
    private int number = 0;
    private int size;
    private float currentX, currentY;
    private List<DeskmediaCanvasUndoStack> mUndoStackList;
    public DeskmediaCanvas(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();

    }
    public DeskmediaCanvas(Context context) {
        super(context);
        initialize();

    }
    public DeskmediaCanvas(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();

    }
    private void initialize() {
        bitmap = Bitmap.createBitmap(AppConfig.SCREEN_WIDTH, AppConfig.SCREEN_HIGHR, Config.ARGB_8888);
        mCanvas = new Canvas();
        mCanvas.setBitmap(bitmap);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mUndoStackList = new ArrayList<>();
        mUndoStackList.add(new DeskmediaCanvasUndoStack());
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//1
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//2
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//3
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//4
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//5
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//6
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//7
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//8
        mUndoStackList.add(new DeskmediaCanvasUndoStack());//9
    }
    public void stopDraw() {
        if (mTimer != null && pathTimer != null) {
            mTimer.cancel();
            pathTimer.cancel();
            mTimer.purge();
            pathTimer.purge();
            mTimer = null;
            pathTimer = null;
        }
    }
    public void startDraw(DcfBean bean) {
        this.mBean = bean;
        mTimer = new Timer();
        length = mBean.getLength();
        startTime = new Date().getTime();
        for (int i = 0; i < mBean.getList().size(); i++) {
            MyTimerTask myTimerTask = new MyTimerTask(new MyHandler(), mBean.getList().get(i), i);
            mTimer.schedule(myTimerTask, 0, 10);
        }
    }
    @SuppressLint("MissingSuperCall")
    @Override
    public void draw(Canvas canvas) {
        canvas.drawBitmap(bitmap, 0, 0, mPaint);
    }
    public void undo(int num) {
        if (mUndoStackList.get(num).canUndo()) {
            int size = mUndoStackList.get(num).undoStack.size();
            int key = mUndoStackList.get(num).undoStack.keyAt(size - 1);
            // todo 第九个用户undoStack和redoStack转换数据
            mUndoStackList.get(9).undoStack.remove(key);
            mUndoStackList.get(9).redoStack.put(key, mUndoStackList.get(num).undoStack.get(key));
            mUndoStackList.get(num).undo();
        }
        mUndoStackList.get(9).rePaint();
    }
    //todo 和undo反过来
    public void redo(int num) {
        if (mUndoStackList.get(num).canRedo()) {
            int size = mUndoStackList.get(num).redoStack.size();
            int key = mUndoStackList.get(num).redoStack.keyAt(0);
            mUndoStackList.get(9).redoStack.remove(key);
            mUndoStackList.get(9).undoStack.put(key, mUndoStackList.get(num).redoStack.get(key));
            mUndoStackList.get(num).redo();
        }
        mUndoStackList.get(9).rePaint();
    }
    // todo 如果num = 1清空mUndoStackList容器中用户
    public void clear(int num) {
        if (num == 1) {
            for (int i = 0; i < mUndoStackList.size(); i++) {
                mUndoStackList.get(i).clearAll();
            }
        }
        invalidate();
    }


    class MyHandler extends Handler {
        private PathBean bean;
        private int i;
        @SuppressLint("WrongCall")
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            bean = (PathBean) bundle.getSerializable("bean");
            i = bundle.getInt("i");
            if (msg.arg1 == 1) {
                switch (bean.getType()) {
                    case AppConfig.PAINT_CLEAR:
                        clear(bean.getNumber());
                        break;
                    case AppConfig.PAINT_UNDO:
                        undo(bean.getNumber());
                        break;
                    case AppConfig.PAINT_REDO:
                        redo(bean.getNumber());
                        break;
                    case AppConfig.PAINT_RECT:
                        Paint paint = getPaint(bean.getColor(), bean.getSize());
                        Path path = new Path();
                        path.addRect(bean.getStartx(), bean.getStarty(), bean.getEndx(), bean.getEndy(), Path.Direction.CW);
                        mCanvas.drawPath(path, paint);
                        savePath(path, paint, bean.getNumber());
                        invalidate();
                        break;
                    case AppConfig.PAINT_OVAL:
                        Paint paint_01 = getPaint(bean.getColor(), bean.getSize());

                        RectF rectf = new RectF();
                        rectf.left = bean.getStartx();
                        rectf.top = bean.getStarty();
                        rectf.right = bean.getEndx();
                        rectf.bottom = bean.getEndy();

                        Path path_01 = new Path();
                        path_01.addOval(rectf, Path.Direction.CW);
                        mCanvas.drawPath(path_01, paint_01);

                        savePath(path_01, paint_01, bean.getNumber());
                        invalidate();
                        break;
                    case AppConfig.PAINT_LINE:
                        Paint paint_02 = getPaint(bean.getColor(), bean.getSize());

                        Path path_02= getLinePath(bean.getmSerPath());
                        mCanvas.drawPath(path_02, paint_02);
                        savePath(path_02, paint_02, bean.getNumber());
                        invalidate();
                        break;
                    case AppConfig.PAINT_PENU:
                        break;
                }
            }

        }
    }
    private Paint getPaint(String color, int size) {
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.parseColor("#" + color));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(size);
        return mPaint;
    }
    private Path getLinePath(SerPath serPath) {
        Path path = new Path();
        SerPoint point = serPath.mPoints.get(0);
        SerPoint point2 = serPath.mPoints.get(1);
        path.moveTo(point.x, point.y);
        path.lineTo(point2.x, point2.y);
        return path;
    }
    private void savePath(Path path, Paint paint, int num) {
        number += 1;
        Bean bean = new Bean(path, paint);
        mUndoStackList.get(num).push(bean, number);
        mUndoStackList.get(9).push(bean, number);
    }
    class MyTimerTask extends TimerTask {
        private long time;
        private MyHandler handler;
        private PathBean bean;
        private int i;
        public MyTimerTask(MyHandler handler, PathBean bean, int i) {
            this.time = bean.getTime();
            this.handler = handler;
            this.bean = bean;
            this.i = i;
        }
        @Override
        public void run() {
            Message message = new Message();
            currentTime = new Date().getTime();
            if ((currentTime - startTime) - time >= 0 && (currentTime - startTime) - time <= 10) {
                message.arg1 = 1;
                Bundle bundle = new Bundle();
                bundle.putSerializable("bean", bean);
                bundle.putInt("i", i);
                message.setData(bundle);
                handler.sendMessage(message);
            }
            long a = currentTime - startTime;
            if ((a - length) >= 0 && (a - length) <= 200) {
                mTimer.cancel();
            }
        }

    }
    class DeskmediaCanvasUndoStack {
        private SparseArray<Bean> undoStack = new SparseArray<>();
        private SparseArray<Bean> redoStack = new SparseArray<>();
        private SparseArray<Bean> removedoStack = new SparseArray<>();
        public DeskmediaCanvasUndoStack() {
            // TODO Auto-generated constructor stub
        }

        public void push(Bean bean, int i) {
            undoStack.put(i, bean);
        }

        public void clearAll() {
            undoStack.clear();
            redoStack.clear();
            removedoStack.clear();

            Paint paint = new Paint();
            paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            mCanvas.drawPaint(paint);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
            invalidate();
        }

        // todo 从 undoStack 取key为最后一个的数据 存储到redoStack里同时删除undoStack key为最后一个的数据
        public void undo() {

            if (canUndo()) {
                Bean bean = undoStack.valueAt(undoStack.size() - 1);
                int key = undoStack.keyAt(undoStack.size() - 1);
                redoStack.put(key, bean);
                undoStack.remove(key);

                Paint paint = new Paint();
                paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
                mCanvas.drawPaint(paint);
                paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
                invalidate();
            }
        }

        // todo 从 redoStack取key为0的数据 存储到undoStack里同时删除redoStack key为0的数据
        public void redo() {
            if (canRedo()) {
                Bean bean = redoStack.valueAt(0);
                int key = redoStack.keyAt(0);

                undoStack.put(key, bean);
                redoStack.remove(key);
                invalidate();
            }

        }

        //todo 取出undoStack容器的内容 绘制在Canvas上
        public void rePaint() {
            for (int i = 0; i < undoStack.size(); i++) {
                Bean bean = undoStack.valueAt(i);
                mCanvas.drawPath(bean.getPath(), bean.getPaint());
            }
            invalidate();

        }

        //todo 判断undoStack容器里面是否有数据
        public boolean canUndo() {
            return (undoStack.size() > 0);
        }

        //todo 判断redoStack容器里面是否有数据
        public boolean canRedo() {
            return (redoStack.size() > 0);
        }
    }

    class Bean {
        private Path path;
        private Paint paint;

        public Bean(Path path, Paint paint) {
            super();
            this.path = path;
            this.paint = paint;
        }

        public Path getPath() {
            return path;
        }

        public void setPath(Path path) {
            this.path = path;
        }

        public Paint getPaint() {
            return paint;
        }

        public void setPaint(Paint paint) {
            this.paint = paint;
        }

    }


}
